package netmodule

import (
	"encoding/binary"
	"go_server/common"
	"io"
	"math/rand"
	"net"
	"time"

	"github.com/astaxie/beego/logs"
	"github.com/google/uuid"
)

func CreateSessionItem(con net.Conn) *common.SessionItem {
	uid := uuid.New().String() //创建uuid，并返回
	newS := new(common.SessionItem)
	newS.Conn = con
	newS.Uuid = uid
	newS.ForHashId = rand.Intn(10000)  //不需要自己手动初始化种子了
	newS.AliveTime = time.Now().Unix() //获取当前时间戳
	return newS
}

//提供创建Session,以及读写函数

func RecvLoop(sessionItem *common.SessionItem) {

	defer func() {
		//这里进行连接资源得到清理---是直接关闭连接，还是发送一个信息给客户端
		TcpServer.SessionGroup.Done()
		TcpServer.RWMtu.Lock()
		delete(TcpServer.SessionMap, sessionItem.Uuid)
		TcpServer.RWMtu.Unlock()
		sessionItem.Conn.Close()
		logs.Info("连接：", sessionItem.Uuid, "断开连接")
	}()
	for {
		select {
		case <-TcpServer.AcceptClose:
			//当TcpServer的AcceptClose管道被close后，所有连接的这个都会触发
			return
		default:
			//这里去接收数据，然后放入队列中执行
			fullMsg, err := readHandler(sessionItem.Conn)
			if err != nil {
				return
			}
			//更新时间
			sessionItem.AliveTime = time.Now().Unix()
			//包装，放入队列里
			AddMsgQueueItemSave(sessionItem, fullMsg)

		}

	}

}

func prasePkgHead(fullMsg *common.PackageStruct, headbuff []byte) error {
	fullMsg.Head = new(common.PackageHead)
	fullMsg.Head.PkgId = binary.BigEndian.Uint16(headbuff[0:2]) //从缓冲区 impl.buff 的当前位置 impl.pos 开始，读取 2 个字节，并将其按照大端序（Big-Endian）的规则解析为一个 uint16 类型的整数值
	fullMsg.Head.PkgBodyLen = binary.BigEndian.Uint32(headbuff[2:6])
	return nil
}

func readHandler(con net.Conn) (*common.PackageStruct, error) {
	//读包头，再读包体
	headBuff := make([]byte, 6) //这里直接硬编码
	_, err := io.ReadAtLeast(con, headBuff[:6], 6)
	if err != nil {
		return nil, common.ErrRead
	}
	//那么进行解析，并拼装
	fullMsg := new(common.PackageStruct)

	err = prasePkgHead(fullMsg, headBuff)
	if err != nil {
		return nil, common.ErrParseHead
	}
	//然后读读取包体
	fullMsg.Body = make([]byte, fullMsg.Head.PkgBodyLen)

	_, err = io.ReadFull(con, fullMsg.Body)
	if err != nil {
		return nil, common.ErrReadBody
	}

	return fullMsg, nil
}
